package com.navinfo.tripanalysis.common.arithmetic;

import com.navinfo.tripanalysis.common.arithmetic.common.CommonData;
import com.navinfo.tripanalysis.common.arithmetic.common.OutStatisticsRangeData.RangeDrivingSlopeStatisticsData;
import com.navinfo.tripanalysis.common.arithmetic.common.OuterStatisticData;
import com.navinfo.tripanalysis.common.arithmetic.common.VarCommon;
import com.navinfo.tripanalysis.common.arithmetic.custom.VarDrivingSlope;
import com.navinfo.tripanalysis.common.arithmetic.custom.VarDrivingSlopeData;
import com.navinfo.tripanalysis.common.arithmetic.custom.VarDrivingSlopeRange;
import com.navinfo.tripanalysis.common.arithmetic.enums.RangeSlopeEnum;
import com.navinfo.tripanalysis.common.arithmetic.manager.AbstractArithmetic;
import com.navinfo.tripanalysis.common.config.ConfigMap;
import com.navinfo.tripanalysis.common.util.ArithmeticUtils;

import java.math.BigDecimal;
import java.util.List;

/**
 * 坡路行驶算法<br/>
 * 依赖{@link Mileage}里程油耗算法<br/>
 * 赋值{@link CommonData#setSlope}的坡度<br/>
 * 输出：统计<br/>
 */
public class DrivingSlopetest extends AbstractArithmetic<VarDrivingSlopeRange> {
    /**
     * 上坡角度最小值
     */
    private BigDecimal uphillGradMin = BigDecimal.valueOf(ConfigMap.getDouble("Uphill_Grad_Min"));
    /**
     * 上坡角度最大值
     */
    private BigDecimal uphillGradMax = BigDecimal.valueOf(ConfigMap.getDouble("Uphill_Grad_Max"));
    /**
     * 平路角度最小值
     */
    private BigDecimal levelRoadGradMin = BigDecimal.valueOf(ConfigMap.getDouble("LevelRoad_Grad_Min"));
    /**
     * 平路角度最大值
     */
    private BigDecimal levelRoadGradMax = BigDecimal.valueOf(ConfigMap.getDouble("LevelRoad_Grad_Max"));
    /**
     * 下坡角度最小值
     */
    private BigDecimal downhillGradMin = BigDecimal.valueOf(ConfigMap.getDouble("Downhill_Grad_Min"));
    /**
     * 下坡角度最大值
     */
    private BigDecimal downhillGradMax = BigDecimal.valueOf(ConfigMap.getDouble("Downhill_Grad_Max"));
    /**
     * 测量坡道距离的极限值 单位:米
     */
    private Integer gradDist = ConfigMap.getInteger("Grad_Dist");

    @Override
    public void calculate() {
        logger.debug("=============进入坡路行驶算法============");
        VarDrivingSlopeRange varDrivingSlope = getObj();
        CommonData commonData = getCommonData();
        List<VarDrivingSlopeData> heightList = varDrivingSlope.getHeightList();

        int height = commonData.getHeight();
        double dffDistance = commonData.getDffMileage();
        logger.debug("Height:{}, dffDistance:{}", height, dffDistance);

        //加入缓存的高度和距离差中
        if (dffDistance > 0) {
            VarDrivingSlopeData slopeData = new VarDrivingSlopeData();
            slopeData.setDffDistance(dffDistance);
            slopeData.setHeight(height);
            heightList.add(slopeData);
        }

        if (heightList.size() > 0) {
            //计算首末点的高度差、距离差
            int diffHeight = heightList.get(heightList.size()-1).getHeight() - heightList.get(0).getHeight();
            double diffDistance = heightList.stream().mapToDouble(e -> e.getDffDistance()).sum();
            logger.debug("diffHeight:{},diffDistance:{}", diffHeight, diffDistance);

            //如果距离大于测量阈值计算坡度
            if (diffDistance >= gradDist) {
                //移除缓存的首点，应该就剩一个末点充当下次计算的首点
                heightList.remove(0);

                //计算坡度数据
                calcSlope(diffHeight, diffDistance);
            }
        }

        logger.debug("===============坡路行驶算法结束=============");
    }

    /**
     * 累加坡度数据
     * @param diffHeight 首末点的高度差
     * @param diffDistance 首末点的距离差
     */
    private void calcSlope(int diffHeight, double diffDistance) {
        VarDrivingSlopeRange var = getObj();
        CommonData commonData = getCommonData();

        //计算坡度
        double slope = (Math.atan2(diffHeight, diffDistance) * 180) / Math.PI;
        BigDecimal slopeBigDecimal = BigDecimal.valueOf(slope);
        logger.debug("slope:{}", slope);

        //将坡度赋值到公共参数中
        commonData.setSlope(slope);

        int dffTime = commonData.getDffTime();
        double dffOil = commonData.getDffFuel();
        double dffDistance = commonData.getDffMileage();

        VarCommon varCommon = null;
        //上坡累加
        if (slopeBigDecimal.compareTo(uphillGradMin) >= 0 && slopeBigDecimal.compareTo(uphillGradMax) <= 0) {
            varCommon = var.getUpSlope();
        }
        //平路累加
        else if (slopeBigDecimal.compareTo(levelRoadGradMin) > 0 && slopeBigDecimal.compareTo(levelRoadGradMax) < 0) {
            varCommon = var.getLevelRoad();
        }
        //下坡累加
        else if (slopeBigDecimal.compareTo(downhillGradMin) >= 0 && slopeBigDecimal.compareTo(downhillGradMax) <= 0) {
            varCommon = var.getDownSlope();
        }

        if(null != varCommon){
            varCommon.addMileage(dffDistance);
            varCommon.addFuel(dffOil);
            varCommon.addDuration(dffTime);
        }

        //按区间累加
        VarCommon varCommon1 = null;
        if(RangeSlopeEnum.Range_F5.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRangeF5();
        }else if(RangeSlopeEnum.Range_F4.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRangeF4();
        }else if(RangeSlopeEnum.Range_F3.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRangeF3();
        }else if(RangeSlopeEnum.Range_F2.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRangeF2();
        }else if(RangeSlopeEnum.Range_F1.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRangeF1();
        }else if(RangeSlopeEnum.Range_0.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRange0();
        }else if(RangeSlopeEnum.Range_1.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRange1();
        }else if(RangeSlopeEnum.Range_2.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRange2();
        }else if(RangeSlopeEnum.Range_3.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRange3();
        }else if(RangeSlopeEnum.Range_4.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRange4();
        }else if(RangeSlopeEnum.Range_5.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRange5();
        }else if(RangeSlopeEnum.Range_Over.getRange().contains(slopeBigDecimal.intValue())){
            varCommon1 = var.getSlopeRangeOver();
        }

        if(null != varCommon1){
            varCommon1.addMileage(dffDistance);
            varCommon1.addFuel(dffOil);
            varCommon1.addDuration(dffTime);
        }


    }

    @Override
    public void collect(OuterStatisticData statisticDataOut) {
        VarDrivingSlopeRange var = super.getObj();
        VarCommon upSlope = var.getUpSlope();
        statisticDataOut.setUpSlopeDrivingMileage(ArithmeticUtils.mileageMToM(upSlope.getMileage()));
        statisticDataOut.setUpSlopeDrivingFuel(ArithmeticUtils.fuelMlToMl(upSlope.getFuel()));
        statisticDataOut.setUpSlopeDrivingDuration(ArithmeticUtils.timeMsToSecond(upSlope.getDuration()));

        VarCommon levelRoad = var.getLevelRoad();
        statisticDataOut.setLevelRoadDrivingMileage(ArithmeticUtils.mileageMToM(levelRoad.getMileage()));
        statisticDataOut.setLevelRoadDrivingFuel(ArithmeticUtils.fuelMlToMl(levelRoad.getFuel()));
        statisticDataOut.setLevelRoadDrivingDuration(ArithmeticUtils.timeMsToSecond(levelRoad.getDuration()));

        VarCommon downSlope = var.getDownSlope();
        statisticDataOut.setDownSlopeDrivingMileage(ArithmeticUtils.mileageMToM(downSlope.getMileage()));
        statisticDataOut.setDownSlopeDrivingFuel(ArithmeticUtils.fuelMlToMl(downSlope.getFuel()));
        statisticDataOut.setDownSlopeDrivingDuration(ArithmeticUtils.timeMsToSecond(downSlope.getDuration()));

        //保存各区间数据
        RangeDrivingSlopeStatisticsData slopedata = new RangeDrivingSlopeStatisticsData();
        VarCommon slopeRangeF5 = var.getSlopeRangeF5();
        slopedata.setSlopeRangeF5_mileage(ArithmeticUtils.mileageMToM(slopeRangeF5.getMileage()));
        slopedata.setSlopeRangeF5_fuel(ArithmeticUtils.fuelMlToMl(slopeRangeF5.getFuel()));
        slopedata.setSlopeRangeF5_duration(ArithmeticUtils.timeMsToSecond(slopeRangeF5.getDuration()));

        VarCommon slopeRangeF4 = var.getSlopeRangeF4();
        slopedata.setSlopeRangeF4_mileage(ArithmeticUtils.mileageMToM(slopeRangeF4.getMileage()));
        slopedata.setSlopeRangeF4_fuel(ArithmeticUtils.fuelMlToMl(slopeRangeF4.getFuel()));
        slopedata.setSlopeRangeF4_duration(ArithmeticUtils.timeMsToSecond(slopeRangeF4.getDuration()));

        VarCommon slopeRangeF3 = var.getSlopeRangeF3();
        slopedata.setSlopeRangeF3_mileage(ArithmeticUtils.mileageMToM(slopeRangeF3.getMileage()));
        slopedata.setSlopeRangeF3_fuel(ArithmeticUtils.fuelMlToMl(slopeRangeF3.getFuel()));
        slopedata.setSlopeRangeF3_duration(ArithmeticUtils.timeMsToSecond(slopeRangeF3.getDuration()));

        VarCommon slopeRangeF2 = var.getSlopeRangeF2();
        slopedata.setSlopeRangeF2_mileage(ArithmeticUtils.mileageMToM(slopeRangeF2.getMileage()));
        slopedata.setSlopeRangeF2_fuel(ArithmeticUtils.fuelMlToMl(slopeRangeF2.getFuel()));
        slopedata.setSlopeRangeF2_duration(ArithmeticUtils.timeMsToSecond(slopeRangeF2.getDuration()));

        VarCommon slopeRangeF1 = var.getSlopeRangeF1();
        slopedata.setSlopeRangeF1_mileage(ArithmeticUtils.mileageMToM(slopeRangeF1.getMileage()));
        slopedata.setSlopeRangeF1_fuel(ArithmeticUtils.fuelMlToMl(slopeRangeF1.getFuel()));
        slopedata.setSlopeRangeF1_duration(ArithmeticUtils.timeMsToSecond(slopeRangeF1.getDuration()));

        VarCommon slopeRange0 = var.getSlopeRange0();
        slopedata.setSlopeRange0_mileage(ArithmeticUtils.mileageMToM(slopeRange0.getMileage()));
        slopedata.setSlopeRange0_fuel(ArithmeticUtils.fuelMlToMl(slopeRange0.getFuel()));
        slopedata.setSlopeRange0_duration(ArithmeticUtils.timeMsToSecond(slopeRange0.getDuration()));

        VarCommon slopeRange1 = var.getSlopeRange1();
        slopedata.setSlopeRange1_mileage(ArithmeticUtils.mileageMToM(slopeRange1.getMileage()));
        slopedata.setSlopeRange1_fuel(ArithmeticUtils.fuelMlToMl(slopeRange1.getFuel()));
        slopedata.setSlopeRange1_duration(ArithmeticUtils.timeMsToSecond(slopeRange1.getDuration()));

        VarCommon slopeRange2 = var.getSlopeRange2();
        slopedata.setSlopeRange2_mileage(ArithmeticUtils.mileageMToM(slopeRange2.getMileage()));
        slopedata.setSlopeRange2_fuel(ArithmeticUtils.fuelMlToMl(slopeRange2.getFuel()));
        slopedata.setSlopeRange2_duration(ArithmeticUtils.timeMsToSecond(slopeRange2.getDuration()));

        VarCommon slopeRange3 = var.getSlopeRange3();
        slopedata.setSlopeRange3_mileage(ArithmeticUtils.mileageMToM(slopeRange3.getMileage()));
        slopedata.setSlopeRange3_fuel(ArithmeticUtils.fuelMlToMl(slopeRange3.getFuel()));
        slopedata.setSlopeRange3_duration(ArithmeticUtils.timeMsToSecond(slopeRange3.getDuration()));

        VarCommon slopeRange4 = var.getSlopeRange4();
        slopedata.setSlopeRange4_mileage(ArithmeticUtils.mileageMToM(slopeRange4.getMileage()));
        slopedata.setSlopeRange4_fuel(ArithmeticUtils.fuelMlToMl(slopeRange4.getFuel()));
        slopedata.setSlopeRange4_duration(ArithmeticUtils.timeMsToSecond(slopeRange4.getDuration()));

        VarCommon slopeRange5 = var.getSlopeRange5();
        slopedata.setSlopeRange5_mileage(ArithmeticUtils.mileageMToM(slopeRange5.getMileage()));
        slopedata.setSlopeRange5_fuel(ArithmeticUtils.fuelMlToMl(slopeRange5.getFuel()));
        slopedata.setSlopeRange5_duration(ArithmeticUtils.timeMsToSecond(slopeRange5.getDuration()));

        VarCommon slopeRangeOver = var.getSlopeRangeOver();
        slopedata.setSlopeRangeOver_mileage(ArithmeticUtils.mileageMToM(slopeRangeOver.getMileage()));
        slopedata.setSlopeRangeOver_fuel(ArithmeticUtils.fuelMlToMl(slopeRangeOver.getFuel()));
        slopedata.setSlopeRangeOver_duration(ArithmeticUtils.timeMsToSecond(slopeRangeOver.getDuration()));

        statisticDataOut.setRangeDrivingSlopeStatisticsData(slopedata);
    }
}
